﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace SBWLogReader
{
    public partial class frmMain : Form
    {               
        private ViewBuilder _viewBuilder;

        public frmMain()
        {
            InitializeComponent();
            _viewBuilder = new ViewBuilder();
            this.cmbBxBandwidthUnits.Items.AddRange(System.Enum.GetNames(typeof(BandwidthUnit)));            
            this.cmbBxBandwidthUnits.SelectedIndex = 2;            
        }

        private void btnAdd_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFile = new OpenFileDialog();
            openFile.Title = "Select the log files...";
            openFile.Filter = "All Files (*.*)|*.*";
            openFile.Multiselect = true;
            if (openFile.ShowDialog() == DialogResult.OK)
            {
                foreach (string file in openFile.FileNames)
                {
                    // Parse the log file and add it to the list
                    LogFile logFile = new LogFile(file);
                    int index = this.listBxLogFiles.Items.Add(logFile);

                    // Check the item
                    this.listBxLogFiles.SetItemChecked(index, true);
                }
            }
        }

        private void btnRemove_Click(object sender, EventArgs e)
        {
            while (this.listBxLogFiles.SelectedIndices.Count > 0)
                this.listBxLogFiles.Items.RemoveAt(this.listBxLogFiles.SelectedIndices[0]);
        }

        private void LoadData()
        {            
            // Clear the old data
            this.tabLogs.TabPages.Clear();
            this.dataGridViewLogs.DataSource = null;

            // Get the selected log files and thier associated log entries
            List<LogFile> logFiles = GetSelectedLogFiles();
            IEnumerable<LogEntry> logEntries = logFiles.SelectMany(l => l.LogEntries);
            List<string> allLogins = logEntries.Select(l => l.Login).Distinct().ToList();
                       
            // Get the user defined settings
            int bytesPerPacket = (int)this.numUpDownBytesPerPacket.Value;
            BandwidthUnit bandwidthUnit = (BandwidthUnit)System.Enum.Parse(typeof(BandwidthUnit), this.cmbBxBandwidthUnits.SelectedItem.ToString());
            List<string> excludedLogins = GetExcludedLoginsList();

            // Filter the log entries to exclude any indciated logins
            logEntries = logEntries.Where(l => !excludedLogins.Contains(l.Login));

            // Load the raw data table
            DataTable table = _viewBuilder.GetRawDataTable(logEntries, bytesPerPacket, bandwidthUnit, excludedLogins);
            LoadAndFormatDataGridView(this.dataGridViewLogs, table, false);
                        
            // Load the summary data for all log files
            LoadSummaryData("All Log Files", logEntries, bytesPerPacket, bandwidthUnit, true);

            // Load the summary data for each of the individual log files
            foreach (LogFile logFile in logFiles)
                LoadSummaryData(logFile.ToString(), logFile.LogEntries.Where(l => !excludedLogins.Contains(l.Login)), bytesPerPacket, bandwidthUnit, true);
           
            // Reload the excluded logins list if a new login file was loaded and new logins were encountered
            // preserving any checked logins 
            this.chkBxExcludedLogins.Items.Clear();
            allLogins.Sort();
            foreach (string login in allLogins)
            {
                int index = this.chkBxExcludedLogins.Items.Add(login);
                if (excludedLogins.Contains(login))
                    this.chkBxExcludedLogins.SetItemChecked(index, true);
            }
        }

        /// <summary>
        /// Adds a summary tab to the tabLogs control for the log entries passed in
        /// </summary>
        /// <param name="tabText"></param>
        /// <param name="logEntries"></param>
        /// <param name="bytesPerPacket"></param>
        /// <param name="bandwidthUnit"></param>
        private void LoadSummaryData(string tabText, IEnumerable<LogEntry> logEntries, int bytesPerPacket, BandwidthUnit bandwidthUnit, bool boldLastRow)
        {
            // Create a new tab
            TabPage tab = new TabPage();
            tab.Text = tabText;

            // Create a new DataGridView 
            DataGridView dataGridView = new DataGridView();
            dataGridView.Dock = DockStyle.Fill;
            dataGridView.AllowUserToAddRows = false;
            dataGridView.AllowUserToDeleteRows = false;
            dataGridView.RowHeadersWidth = 20;
            dataGridView.ReadOnly = true;
            tab.Controls.Add(dataGridView);

            this.tabLogs.TabPages.Add(tab);

            // Generate the data
            DataTable dataTable = _viewBuilder.GetSummaryDataTable(logEntries, bytesPerPacket, bandwidthUnit, this.radBtnHour.Checked);
            LoadAndFormatDataGridView(dataGridView, dataTable, boldLastRow);
        }

        /// <summary>
        /// Loads and formats the data in the specified DataGridView according to the types of the columns in the DataTable
        /// </summary>
        /// <param name="dataGrid"></param>
        /// <param name="table"></param>
        private void LoadAndFormatDataGridView(DataGridView dataGrid, DataTable table, bool boldLastRow)
        {
            dataGrid.DataSource = table;

            for (int i = 0; i < table.Columns.Count; i++)
            {
                DataColumn clm = table.Columns[i];

                dataGrid.Columns[i].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;

                if (clm.DataType == typeof(decimal))
                {
                    dataGrid.Columns[i].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
                    dataGrid.Columns[i].DefaultCellStyle.Format = "N2";
                }
                else if (clm.DataType == typeof(int))
                {
                    dataGrid.Columns[i].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
                    dataGrid.Columns[i].DefaultCellStyle.Format = "N0";
                }
            }           

            if(boldLastRow)                            
                dataGrid.Rows[dataGrid.Rows.Count - 1].DefaultCellStyle.Font = new Font(dataGrid.DefaultCellStyle.Font, FontStyle.Bold);            
        }

        /// <summary>
        /// Gets a list of logins the user does not want to include in the displays
        /// </summary>
        /// <returns></returns>
        private List<string> GetExcludedLoginsList()
        {
            List<string> excludedLogins = new List<string>();

            foreach (string login in this.chkBxExcludedLogins.CheckedItems)
                excludedLogins.Add(login);

            return excludedLogins;
        }

        /// <summary>
        /// Gets a list of LogFile objects associated with the log files the user has checked
        /// </summary>
        /// <returns></returns>
        private List<LogFile> GetSelectedLogFiles()
        {
            List<LogFile> logFiles = new List<LogFile>();

            foreach (LogFile logFile in this.listBxLogFiles.CheckedItems)                
                logFiles.Add(logFile);
            
            return logFiles;
        }
    
        private void btnGo_Click(object sender, EventArgs e)
        {
            LoadData();
        }       
    }
}
